function compile(selector) {
  const node = document.querySelector(selector);
  if (node) {
    console.log(node);
  }
}

class Compile {
  constructor(vm, selector) {
    this.vm = vm;
    this.node = document.querySelector(selector);
    this.compile(this.node);
  }
  compile(node) {
    // console.log(node, node.childNodes);
    if (this.isElemetNode(node)) {
      // 判断是否是指令
      const attrs = Array.from(node.attributes);
      attrs.forEach((attr) => {
        const { name, value } = attr;
        if (this.isDirective(name)) {
          const vmVal = this.getVmValue(value);
          this.update(node, value, vmVal, name.slice(2));
        }
      });
      [].forEach.call(node.childNodes, (childNode) => {
        this.compile(childNode);
      });
    } else if (this.isTextExp(node)) {
      this.compileText(node);
    }
  }
  update(node, key, val, exp) {
    const fn = this[exp + 'Updater'];
    fn && fn(node, val);
    new Watcher(this.vm, key, (newVal) => {
      console.log('update:', newVal);
      fn && fn(node, newVal);
    });
  }

  compileText(node) {
    const key = RegExp.$1;
    const val = this.getVmValue(key);
    const reg = new RegExp(`{{${key}}}`, 'g');
    const content = node.textContent.replace(reg, val);
    this.update(node, key, content, 'text');
  }

  textUpdater(node, val) {
    node.textContent = val;
  }
  htmlUpdater(node, val) {
    node.innerHTML = val;
  }
  isDirective(name) {
    return name.startsWith('v-');
  }
  isElemetNode(node) {
    return node.nodeType === 1;
  }
  isTextExp(node) {
    return node.nodeType === 3 && /\{\{(.*)\}\}/.test(node.textContent);
  }

  getVmValue(key) {
    const names = key.split('.');
    return names.reduce((result, name) => {
      return result[name];
    }, this.vm);
  }
}

//  收集依赖
class Dep {
  constructor() {
    this.deps = [];
  }
  addDep(watcher) {
    this.deps.push(watcher);
  }
  notify() {
    this.deps.forEach((watcher) => {
      if (watcher && typeof watcher.update === 'function') {
        watcher.update();
      }
    });
  }
}

class Watcher {
  constructor(vm, key, updater) {
    this.vm = vm;
    this.key = key;
    this.updater = updater;
    Dep.target = this;
    this.value = this.getValue();
    Dep.target = null;
  }

  getValue() {
    return this.vm[this.key];
  }

  update() {
    const newVal =  this.getValue();
    console.log('newVal:', newVal);
    this.updater && this.updater(newVal);
  }
}
